#include "linda.h"

linda_space* linda_create(const char *path){
    int n = 1, fd;
    linda_space* new_space = (linda_space*)malloc(sizeof(linda_space));
    new_space->path = path;
    char buf[80];
    mkdir(path, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); // na wszeli
    chdir(path);

    _linda_create_rw_lock("m_lock", &(new_space->lock));

    FILE* lfc = fopen("lindac", "wb");
    fwrite(&n, sizeof(int), 1, lfc);
    fclose(lfc);

    mkdir("pattern", S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
    mkdir("tuple", S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);



    chdir("..");
    chdir("..");
    return new_space;
}

linda_space* linda_init(const char *path){
    int n;
    linda_space* new_space = (linda_space*)malloc(sizeof(linda_space));
    new_space->path = path;
    chdir(path);
    _linda_get_rw_lock("m_lock", &(new_space->lock));
    _linda_lock_writer(&(new_space->lock));

    FILE* lfc = fopen("lindac", "r+b");
    fread(&n, sizeof(int), 1, lfc);
    fseak(lfc, 0L, SEEK_SET);
    n++;
    fwrite(&n, sizeof(int), 1, lfc);
    fclose(lfc);
    chdir("..");
    chdir("..");
    _linda_release_writer(&(new_space->lock));
    return new_space;


}

void linda_close(const linda_space * linda){
    int n;
    _linda_lock_writer(&(linda->lock));
    chdir(linda->path);
    FILE* lfc = fopen("lindac", "r+b");
    fread(&n, sizeof(int), 1, lfc);
    fseak(lfc, 0L, SEEK_SET);
    n--;
    fwrite(&n, sizeof(int), 1, lfc);
    fclose(lfc);
    _linda_release_writer(&(linda->lock));
    if(n==0){
        _linda_destroy_rw_lock(&(linda->lock));
        remove("tuple");
        remove("pattern");
        remove("lindac");
    }

}



tuple* linda_input(const linda_space * linda, pattern * pat , int timeout){
    DIR* d;
    struct dirent* dir_ent;
    int pat_n=0;
    char buf [80];
    tuple *tup=NULL;
    _linda_lock_writer(&(linda->lock));
    d = opendir("tuple");
    while(dir_ent=readdir(d)){
        delete_tuple(tup);
        tup=read_tuple(dir_ent->d_name);
        if(comparison(pat, tup)){
            closedir(d);
            _linda_release_writer(&(linda->lock));
            return tup;
        }
    }
    delete_tuple(tup);
    chdir("..");

    d = opendir("pattern");
    while(dir_ent=readdir(d))
        (strcmp(itoa(++pat_n, buf, 10), dir_ent->d_name)==0)?continue:break;
    pat_n++;
    closedir(d);

    chdir("pattern");
    pat->pattern_type=INPUT_PATTERN;

    write_pattern(itoa(pat_n, buf, 10), pat);

    _linda_rw_condition cond;
    _linda_create_rw_condition(&(linda->lock),buf,&cond);

    d = opendir("tuple");
    while(_linda_writer_wait_condidion(linda->cond)){
        rewinddir(d);
        while(dir_ent=readdir(d)){
            delete_tuple(tup);
            tup=read_tuple(dir_ent->d_name);
            if(comparison(pat, tup)){
                closedir(d);
                _linda_destroy_rw_condition(cond);
                unlink(buf);
                _linda_release_writer(&(linda->lock));
                return tup;
            }
        }
    }
    _linda_destroy_rw_condition(cond);
    unlink(buf);
    _linda_release_writer(linda->lock);
    return NULL;
}

tuple* linda_read(const linda_space * linda, const pattern * pat , int timeout){

    DIR* d;
    struct dirent* dir_ent;
    int pat_n=0, pid;
    char buf [80];
    tuple *tup=NULL;
    _linda_lock_reader(&(linda->lock));
    chdir(linda->path);
    d = opendir("tuple");
    while(dir_ent=readdir(d)){
        delete_tuple(tup);
        tup=read_tuple(dir_ent->d_name);
        if(comparison(pat, tup)){
            closedir(d);
            _linda_release_reader(&(linda->lock));
            return tup;
        }
    }

    //nie znaleziono krotki
    _linda_release_reader(&(linda->lock));
    _linda_lock_writer(&(linda->lock));
    rewinddir(d);
    while(dir_ent=readdir(d)){
        delete_tuple(tup);
        tup=read_tuple(dir_ent->d_name);
        if(comparison(pat, tup)){
            closedir(d);
            _linda_release_writer(&(linda->lock));
            return tup;
        }
    }
    delete_tuple(tup);
    chdir("..");

    d = opendir("pattern");
    while(dir_ent=readdir(d))
        (strcmp(itoa(++pat_n, buf, 10), dir_ent->d_name)==0)?continue:break;
    pat_n++;
    closedir(d);

    chdir("pattern");
    pat->pattern_type=READ_PATTERN;

    write_pattern(itoa(pat_n, buf, 10), pat);

    _linda_rw_condition cond;
    _linda_create_rw_condition(&(linda->lock),buf,&cond);

    d = opendir("tuple");
    while(_linda_writer_wait_condidion(linda->cond)){
        rewinddir(d);
        while(dir_ent=readdir(d)){
            delete_tuple(tup);
            tup=read_tuple(dir_ent->d_name);
            if(comparison(pat, tup)){
                closedir(d);
                _linda_destroy_rw_condition(cond);
                unlink(buf);
                _linda_release_writer(&(linda->lock));
                return tup;
            }
        }
    }
    _linda_destroy_rw_condition(cond);
    unlink(buf);
    _linda_release_writer(&(linda->lock));
    return NULL;

}

void linda_output(const linda_space * linda,const  tuple * t){
    DIR* d;
    struct dirent* dir_ent;
    int tup_n=1;
    char buf [80];
    _linda_rw_condition* cond;
    pattern * d_pat = NULL, * pat;

    _linda_lock_writer(linda->lock);
    chdir(linda->path);
    d = opendir("tuple");
    while(dir_ent=readdir(d))
        (strcmp(itoa(++pat_n, buf, 10), dir_ent->d_name)==0)?continue:break;
    itoa(++tup_n, buf, 10);
    closedir(d);
    chdir("tuple");

    write_tuple(buf, t);

    chdir("../pattern");
    d = opendir("../pattern");

    while(dir_ent=readdir(d)){
            delete_pattern(pat);
            pat=read_pattern(dir_ent->d_name);
            if(comparison(pat, t)){
                if(pat->pattern_type == READ_PATTERN){
                    _linda_get_rw_condition(&(linda->lock),dir_ent->d_name,cond );
                    _linda_writer_signal_condidion(cond);
                }
                else{};
            }
        }


}
